package spring.lottery.server.imp;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import spring.lottery.common.exception.ServerException;
import spring.lottery.common.util.RedisUtil;
import spring.lottery.common.util.SerializeUtil;
import spring.lottery.controller.param.DrawPrizesData;
import spring.lottery.dao.dataObject.ActivityPrizeDO;
import spring.lottery.dao.dataObject.PrizeDO;
import spring.lottery.dao.mapper.*;
import spring.lottery.server.ActivitiesServer;
import spring.lottery.server.DrawPrizeServer;
import spring.lottery.server.dto.*;
import spring.lottery.server.enums.ActivityStatusEnum;
import spring.lottery.server.exceptionCode.ServerConstantCode;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static spring.lottery.common.config.DirectRabbitConfig.EXCHANGE_NAME;
import static spring.lottery.common.config.DirectRabbitConfig.ROUTING;

@Slf4j
@Service
public class DrawPrizeServerImp implements DrawPrizeServer {
    private static final String CREATE_ACTIVITY = "CREATE_ACTIVITY";

    ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    RedisUtil redisUtil;
    @Autowired
    ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    ActivityUserMapper activityUserMapper;
    @Autowired
    ActivitiesServer activitiesServer;
    @Autowired
    ActivityMapper activityMapper;
    @Autowired
    ActivityUserMapper activityUserDao;
    @Autowired
    PrizeMapper prizeMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WinningRecordMapper winningRecordMapper;

    @Override
    public ActivityInf find(Long activityId) {
        //先从redis中找
        String s = redisUtil.get(CREATE_ACTIVITY + activityId);
        if (s != null) {
            try {
                ActivityInf activityInf = objectMapper.readValue(s, ActivityInf.class);

                log.info("redis中返回的users和prizes {}", activityInf.toString());

                return activityInf;
            } catch (JsonProcessingException e) {
                log.error("格式转换失败 json to ActivityInf {}", e.getMessage(), e);
                return null;
            }
        }

        //没有机查库并加到redis中
        /**
         *  ActivityDto activity;
         *     List<ActivityPrizeInf> activityPrizeList;
         *     List<UserDto> activityUserList;
         */
        ActivityInf activityInf = getActivityInfo(activityId);

        //放到redis中
        String toRedis = SerializeUtil.encode(activityInf);

        log.info("redis中没有，重新查询到的数据： {}", toRedis);

        redisUtil.set(CREATE_ACTIVITY + activityId, toRedis);

        return activityInf;
    }


    public ActivityInf getActivityInfo(Long activityId) {

//      ActivityDto activity;
        ActivityDto ac = activityMapper.selectActivityById(activityId);

        if (ac == null) {
            log.error("活动不存在 activityId {}", activityId);
            throw new ServerException(ServerConstantCode.ACTIVITY_NOT_EXIST);
        }

        //和活动关联的人员信息
        List<UserDto> acUI = getActivityUserInfo(activityId);

        if (acUI == null) {
            log.error("和活动关联的人员不存在 activityId {}", activityId);
            throw new ServerException(ServerConstantCode.USER_NOT_EXIST);
        }

        //和活动关联的奖品信息
        List<ActivityPrizeDO> activityPrizes = activityPrizeMapper.selectById(activityId);

        if (activityPrizes == null) {
            log.error("和活动关联的奖品不存在 activityId {}", activityId);
            throw new ServerException(ServerConstantCode.PRIZE_NOT_EXIST);
        }


        //Activity 奖品的信息
        List<Long> collect = activityPrizes.stream().map(ActivityPrizeDO::getPrizeId)
                .collect(Collectors.toList());

        List<PrizeDO> prizes = prizeMapper.selectByIds(collect);

        if(prizes == null) {
            log.error("奖品不存在 userIds {}", collect);
            throw new ServerException(ServerConstantCode.PRIZE_NOT_EXIST);
        }

        //将PrizeDto和ActivityPrizeDto的信息整合到ActivityPrizeInf中
        List<ActivityPrizeInf> acPI = convertToActivityPrizeInf(activityPrizes, prizes);

        ActivityInf activityInf = new ActivityInf(ac, acPI, acUI);

        log.info("重新查到的 activityInf {}", activityInf.toString());

        return activityInf;
    }

    @Override
    public void sendToMq(DrawPrizesData drawPrizesData) {
        String msg = SerializeUtil.encode(drawPrizesData);

        log.info("生产者 发送给交换机：{} 绑定的匹配键：{} 内容：{}", EXCHANGE_NAME, ROUTING, msg);

        rabbitTemplate.convertAndSend(EXCHANGE_NAME, ROUTING, msg);
    }

    /**
     * {"activityId":40,"prizeId":73,"winningTime":1749713195136,
     * "winnerList":[{"userId":60,"userName":"zxdc"}]}
     */
    @Override
    public void verify(DrawPrizesData prizesData) {
        //活动是否存在
        ActivityDto activity = activityMapper.selectActivityById(prizesData.getActivityId());

        //奖品是否和活动关联 还有奖品的状态
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(prizesData.getActivityId(), prizesData.getPrizeId());

        if (activity == null ) {
            log.error("该活动不存在 prizeInfo: {}",prizesData);
            throw new ServerException(ServerConstantCode.ACTIVITY_NOT_EXIST);
        }

        if(ActivityStatusEnum.COMPLETED.equals(activity.getStatus())){
            log.error("活动已经结束 prizeInfo: {}", prizesData);
            throw new ServerException(ServerConstantCode.ACTIVITY_IS_COMPLETED);
        }

        //判断奖品信息是否存在
        if (activityPrizeDO == null ) {
            log.error("该奖品不存在 prizeInfo: {}",prizesData);
            throw new ServerException(ServerConstantCode.PRIZE_NOT_EXIST,"prizeId = " +prizesData.getPrizeId().toString());
        }

        if (ActivityStatusEnum.COMPLETED.equals(activityPrizeDO.getStatus())) {
            log.error("该奖品已经被抽完了 prize: {}", activityPrizeDO);
            throw new ServerException(ServerConstantCode.PRIZE_IS_EXTRACTED);
        }

        //奖品是否存在，是否和中奖的一致
        //人员是否存在 这个人是否是没有中过将的
        List<DrawPrizesData.LuckUserList> winnerList = prizesData.getWinnerList();

        List<Long> list = winnerList.stream().map(DrawPrizesData.LuckUserList::getUserId).collect(Collectors.toList());

        List<ActivityUserDto> users = activityUserMapper.getUsersByAUIds(prizesData.getActivityId(), list);

        if (users.isEmpty()) {
            log.error("该人员不存在 prizeInfo: {}",prizesData);
            throw new ServerException(ServerConstantCode.USER_NOT_EXIST, "id=" + prizesData.getPrizeId());
        }

        //人员要是没有中奖的，且人数要和奖品数量相同
        if (activityPrizeDO.getPrizeAmount() != winnerList.size()) {
            log.error("中奖人数和奖品数量不对 prizeId: {} prizeAmount: {}  winners: {}",
                    prizesData.getPrizeId(), activityPrizeDO.getPrizeAmount(), users.size());
            throw new ServerException(ServerConstantCode.USER_PRIZES_MISMATCH);
        }

        //所有人都要是未中奖的
        for(ActivityUserDto user : users){
            if (ActivityStatusEnum.USER_COMPLETED.equals(user.getStatus())) {
                log.error("该人员已经中奖 userInfo: {}", user);
                throw new ServerException(ServerConstantCode.USER_IS_WINNER);
            }
        }
    }

    @Override
    public void updateRedis(DrawPrizesData param) {

        ActivityInf activityInfo = getActivityInfo(param.getActivityId());

        if(activityInfo == null){
            log.info("重新查询到的活动信息为空");
            throw new ServerException(ServerConstantCode.ACTIVITY_NOT_EXIST);
        }

        String encode = SerializeUtil.encode(activityInfo);

        redisUtil.set(CREATE_ACTIVITY + param.getActivityId(), encode);

        log.info("跟新到redis中的值为 key= {}  value= {}", CREATE_ACTIVITY + param.getActivityId(), encode);
    }


    /**
     *
     * @return List: winnerName prizeName prizeTier
     */
    @Override
    public List<WinningsDto> showWinning(Map<String,String> params) {

        if (params.size() > 1) {
            String prizeIds = params.get("prizeId");

            log.info("这个是俩个参数的查询 prizeIds {}", prizeIds);

//            List list = SerializeUtil.unEncode(prizeIds, List.class);
            return null;

        }

        Long activityId = Long.parseLong(params.get("activityId"));

        List<WinningsDto> w = winningRecordMapper.selectByActivityId(activityId);

        log.info("查询到的中奖信息: {}", w);

        return w;
    }

    private List<UserDto> getActivityUserInfo(Long activityId) {

        List<ActivityUserDto> users = activityUserMapper.selectUsersById(activityId);

        List<UserDto> userDtos = userMapper.selectByIds(
                users.stream()
                        .map(ActivityUserDto::getUserId)
                        .collect(Collectors.toList()));

        log.info("查到的和活动关联的用户的信息 {}", userDtos);

        return userDtos;
    }


    private List<ActivityPrizeInf> convertToActivityPrizeInf(List<ActivityPrizeDO> activityPrizes, List<PrizeDO> prizes) {
        List<ActivityPrizeInf> acI = new ArrayList<>();

        for (int i = 0; i < prizes.size(); i++) {
            ActivityPrizeDO acPrize = activityPrizes.get(i);

            PrizeDO prize = prizes.get(i);

            ActivityPrizeInf activityPrizeInf = new ActivityPrizeInf(prize.getId(),prize.getName(),
                    prize.getDescription(), prize.getPrice(), prize.getImageUrl(),
                    acPrize.getPrizeAmount(), acPrize.getPrizeTiers(),true);

            acI.add(activityPrizeInf);
        }

        log.info("整合ActivityPrize和prize信息的结果 ActivityPrize：{}\nprize: {}\nacI:{}", activityPrizes, prizes, acI);

        return acI;
    }
}
